package validate

import (
	"fmt"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/locales/en"
	"github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	enTranslations "github.com/go-playground/validator/v10/translations/en"
	zhTranslations "github.com/go-playground/validator/v10/translations/zh"
	"go-shop-api/internal/service"
	"reflect"
	"strings"
)

//验证器

//文档
//https://www.liwenzhou.com/posts/Go/validator_usages/
//https://github.com/Q1mi/validator_demo/blob/master/gin_demo.go
//https://pkg.go.dev/github.com/go-playground/validator/v10
//https://github.com/go-playground/validator

// Trans 定义一个全局翻译器T
var trans ut.Translator

// InitTrans 初始化翻译器
func initTrans(locale string) (err error) {
	// 修改gin框架中的Validator引擎属性，实现自定制
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {

		// 注册一个获取json tag的自定义方法
		//效果  结构体字段名的大写变为了json格式里面的小写
		//      "ValidatorService.Age": "Age必须大于或等于1",
		// ==>  "ValidatorService.age": "age必须大于或等于1",
		v.RegisterTagNameFunc(func(fld reflect.StructField) string {
			name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
			if name == "-" {
				return ""
			}
			return name
		})

		// 为【自定义[结构体]校验方法】注册自定义校验方法
		v.RegisterStructValidation(ValidatorValidation, service.ValidatorService{})
		//	"re_password": "re_password必须等于Password"       == >            "re_password": "re_password必须等于password"

		v.RegisterStructValidation(UserStructValidation, service.UserService{})

		//【自定义字段校验方法】
		// 在校验器注册自定义的校验方法
		if err = v.RegisterValidation("checkDate", customFunc); err != nil {
			return err
		}
		if err = v.RegisterValidation("checkPhone", checkPhoneFunc); err != nil {
			return err
		}

		zhT := zh.New() // 中文翻译器
		enT := en.New() // 英文翻译器

		// 第一个参数是备用（fallback）的语言环境
		// 后面的参数是应该支持的语言环境（支持多个）
		// uni := ut.New(zhT, zhT) 也是可以的
		uni := ut.New(enT, zhT, enT)

		// locale 通常取决于 http 请求头的 'Accept-Language'
		var ok bool
		// 也可以使用 uni.FindTranslator(...) 传入多个locale进行查找
		trans, ok = uni.GetTranslator(locale)
		if !ok {
			return fmt.Errorf("uni.GetTranslator(%s) failed", locale)
		}

		// 注册翻译器
		switch locale {
		case "en":
			err = enTranslations.RegisterDefaultTranslations(v, trans)
		case "zh":
			err = zhTranslations.RegisterDefaultTranslations(v, trans)
		default:
			err = enTranslations.RegisterDefaultTranslations(v, trans)
		}

		if err != nil {
			return err
		}

		//【自定义翻译方法】
		// 注意！因为这里会使用到trans实例
		// 所以这一步注册要放到trans初始化的后面
		if err = v.RegisterTranslation(
			"checkDate",
			trans,
			registerTranslator("checkDate", "{0}必须要晚于当前日期/格式错误"),
			translate,
		); err != nil {
			return err
		}

		if err = v.RegisterTranslation(
			"checkPhone",
			trans,
			registerTranslator("checkPhone", "手机号不正确"),
			translate,
		); err != nil {
			return err
		}

		//        "phone": "Key: 'UserService.phone' Error:Field validation for 'phone' failed on the 'checkPhone' tag"
		//		==>
		//        "phone": "手机号不正确"

		return
	}
	return
}

// RemoveTopStruct 定义一个去掉结构体名称前缀的自定义方法：
/*

	//    "data": {
	//        "ValidatorService.age": "age必须大于或等于1",
	//        "ValidatorService.email": "email为必填字段",
	//        "ValidatorService.name": "name为必填字段",
	//        "ValidatorService.password": "password为必填字段",
	//        "ValidatorService.re_password": "re_password为必填字段"
	//    }

			=====>

	//    "data": {
	//        "age": "age必须大于或等于1",
	//        "email": "email为必填字段",
	//        "name": "name为必填字段",
	//        "password": "password为必填字段",
	//        "re_password": "re_password为必填字段"
	//    }

*/
func RemoveTopStruct(fields map[string]string) map[string]string {
	res := map[string]string{}
	for field, err := range fields {
		res[field[strings.Index(field, ".")+1:]] = err
	}
	return res
}

// registerTranslator 为自定义字段添加翻译功能
func registerTranslator(tag string, msg string) validator.RegisterTranslationsFunc {
	return func(trans ut.Translator) error {
		if err := trans.Add(tag, msg, false); err != nil {
			return err
		}
		return nil
	}
}

// translate 自定义字段的翻译方法
func translate(trans ut.Translator, fe validator.FieldError) string {
	msg, err := trans.T(fe.Tag(), fe.Field())
	if err != nil {
		panic(fe.(error).Error())
	}
	return msg
}

// GetValidatorTrans 获取Trans
func GetValidatorTrans() ut.Translator {
	return trans
}

// InitTranslator 初始化翻译器
func InitTranslator(locale string) {
	if err := initTrans(locale); err != nil {
		//fmt.Printf("init trans failed, err:%v\n", err)
		//os.Exit(1)
		panic("init trans failed, err:%v\n" + err.Error())
	}
}
